package ws

import (
	"dmsv/common"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/beego/beego/v2/core/logs"
	"github.com/gorilla/websocket"
	"sync"
	"time"
)

var gAllClient sync.Map

const (
	event_register      = "register"
	event_response      = "regResponse"
	event_heartbeat     = "heartbeat"
	event_status_set    = "setStatus"
	event_status_get    = "getStatus"
	event_status_change = "statusChange"
	event_new_call      = "newCall"
	event_message       = "message"
	event_set_busy      = "setBusy"
)

type WsClient struct {
	AppId      string
	ServiceId  string
	SipAcct    string
	lastHeart  time.Time
	conn       *websocket.Conn
	locker     *sync.Mutex
	reSendChan chan (*event)
	msgChan    chan common.Message
}

type event struct {
	Event     string      `json:"event"`
	TimeStamp string      `json:"timeStamp"`
	AppId     string      `json:"appId"`
	Data      interface{} `json:"data"`
}

type newCallInfo struct {
	Caller   string `json:"caller"`
	Callee   string `json:"number"`
	CallId   string `json:"callId"`
	CallType string `json:"callType"`
}

type register struct {
	SipAcct   string `json:"sipAcct"`
	ServiceId string `json:"serviceId"`
}

func NewRegister(newClient *websocket.Conn) (*WsClient, error) {

	msg := event{}
	msg.Data = register{}
	_, recvEvent, err := newClient.ReadMessage()
	if err != nil {
		logs.Error("register msg invlid:%v", err)
		return nil, fmt.Errorf("接收失败")
	}

	err = json.Unmarshal(recvEvent, &msg)
	if err != nil {
		logs.Error("register msg invlid:%v,%v", err, string(recvEvent))
		return nil, fmt.Errorf("参数类型不正确")
	}

	if msg.Event != event_register {
		logs.Error("event invlid:%v,%v", string(recvEvent))
		return nil, fmt.Errorf("第一次连接需要先注册")
	}

	regInfo := msg.Data.(map[string]interface{})
	sipAcct := regInfo["sipAcct"].(string)
	if len(sipAcct) == 0 {
		logs.Error("注册sip账号为空：%v ", msg.Data)
		return nil, fmt.Errorf("sip账号为空")
	}

	newWs := &WsClient{}

	tmp, ok := gAllClient.Load(sipAcct)
	if ok {
		newWs = tmp.(*WsClient)

		newWs.locker.Lock()
		newWs.conn = newClient
		newWs.locker.Unlock()

	} else {
		newWs = &WsClient{
			AppId:      msg.AppId,
			ServiceId:  regInfo["serviceId"].(string),
			SipAcct:    sipAcct,
			conn:       newClient,
			locker:     new(sync.Mutex),
			lastHeart:  time.Now(),
			reSendChan: make(chan *event, 10),
		}
		//启动超时检测线程
		newWs.timeOutDetect()

	}
	//启动接收处理线程
	newWs.receiveProcess(newWs.conn)

	//保存 - 后续需要同步到redis
	gAllClient.Store(newWs.SipAcct, newWs)

	//响应注册报文
	newWs.sendRegResponse()

	logs.Debug("坐席注册:%v, sipAcct:%v from:%v", newWs.ServiceId, newWs.SipAcct, newClient.RemoteAddr().String())
	return newWs, nil
}

func (this *WsClient) resendTask() {

	go func() {

		for {

			msg, ok := <-this.reSendChan
			if !ok {
				logs.Debug("[%v]serviceId[%v]resend task close.", this.AppId, this.ServiceId)
				return
			}

			msgStart, _ := time.Parse("2006-01-02 15:04:05.000", msg.TimeStamp)
			if time.Since(msgStart) < 2*time.Second {

				this.locker.Lock()
				if this.conn == nil {
					logs.Error("appId:%v,service:%v,sipAcct:%v is down", this.AppId, this.ServiceId, this.SipAcct)

					time.Sleep(500 * time.Millisecond)
					this.reSendChan <- msg
				}

				this.conn.WriteJSON(msg)
				this.locker.Unlock()
			}
		}
	}()
}

func (this *WsClient) timeOutDetect() {

	go func() {

		logs.Debug("appId:%v serviceId:%v 启动心跳检测任务", this.AppId, this.ServiceId)
		for {
			time.Sleep(5 * time.Second)
			t := time.Since(this.lastHeart)
			if t > 100*time.Second {
				logs.Error("app:%v service:%v sipAcct:%v is time out from:%v ,last:%v",
					this.AppId, this.ServiceId, this.SipAcct, this.lastHeart.Format("20060102150405"), t.Seconds())

				//关闭连接
				this.locker.Lock()
				if this.conn != nil {

					this.conn.Close()
					this.conn = nil
				}
				this.locker.Unlock()

				//发送超时的消息
				timeOutMsg := common.Message{
					Event: common.EVT_TIMEOUT,
				}

				this.locker.Lock()
				if nil != this.msgChan {
					this.msgChan <- timeOutMsg
				} else {
					logs.Error("appId[%v]service[%v] have no msg channel.", this.AppId, this.ServiceId)
				}
				this.locker.Unlock()
				//从存储中删除
				gAllClient.Delete(this.SipAcct)

				break
			}
		}
	}()
}

func (this *WsClient) BindMsgChan(msgChan chan common.Message) {
	logs.Debug("[%v]serviceId[%v]绑定消息通道", this.AppId, this.ServiceId)
	this.msgChan = msgChan
}

func (this *WsClient) RemoveMsgChan() {
	logs.Debug("[%v]serviceId[%v]移除消息通道", this.AppId, this.ServiceId)
	this.locker.Lock()
	this.msgChan = nil
	this.locker.Unlock()
}

//接收信息处理线程
func (this *WsClient) receiveProcess(conn *websocket.Conn) {

	go func() {
		msg := event{}
		for {

			count, data, rdErr := conn.ReadMessage()
			if rdErr != nil {
				logs.Error("坐席[%v] receive  err:%v", this.ServiceId, rdErr.Error())

				break
			}

			if count > 0 {
				err := json.Unmarshal(data, &msg)
				if err != nil {
					logs.Error("[%v] json failed:%v,close channel", string(data), err)
					break
				}
			}

			//收到报文即更新心跳时间
			this.lastHeart = time.Now()

			switch msg.Event {
			case event_heartbeat:
				//logs.Debug("坐席[%v]收到心跳报文:%v", this.ServiceId, string(data))
				//心跳报文,实时响应
				this.sendHeartResponse()
			case event_status_set:
				//设置状态
				//this.MessageChan <- msg.Data.(string)
			default:
				logs.Debug("收到其他消息:%v", string(data))
			}
		}

		this.locker.Lock()
		defer this.locker.Unlock()

		if this.conn == nil {
			return
		}

		err := this.conn.Close()
		if err != nil {
			logs.Error("坐席[%v] close channel failed:%v", this.ServiceId, err)
		}
		this.conn = nil

	}()
}

func (this *WsClient) sendMsg(msgType string, data interface{}) error {

	msg := event{
		Event:     msgType,
		TimeStamp: time.Now().Format("2006-01-02 15:04:05.000"),
		AppId:     this.AppId,
		Data:      data,
	}

	this.locker.Lock()
	defer this.locker.Unlock()
	if this.conn == nil {
		logs.Error("appId:%v,service:%v,sipAcct:%v is down", this.AppId, this.ServiceId, this.SipAcct)

		//this.reSendChan <- &msg
		return errors.New("connClose")
	}

	return this.conn.WriteJSON(msg)
}

//注册响应
func (this *WsClient) sendRegResponse() {

	err := this.sendMsg(event_response, "")
	if err != nil {
		logs.Error("注册返回err:%v", err)
	}
}

//心跳报文
func (this *WsClient) sendHeartResponse() {

	err := this.sendMsg(event_heartbeat, "")
	if err != nil {
		logs.Error("发送心跳报文err:%v", err)
	}
	//logs.Debug("[%v]发送心跳报文成功...", this.ServiceId)
}

//设置状态
func (this *WsClient) SendSetBusy() {

	err := this.sendMsg(event_set_busy, "")
	if err != nil {
		logs.Error("发送示忙 err:%v", err)
	}
}

//设置状态
func (this *WsClient) StatusChange() {

	err := this.sendMsg(event_status_change, "")
	if err != nil {
		logs.Error("发送状态变更 err:%v", err)
	}
}

//发送呼入消息
func (this *WsClient) SendNewCallRpt(callId, caller, callee, callType string) {

	callMsg := newCallInfo{
		CallId:   callId,
		Callee:   callee,
		Caller:   caller,
		CallType: callType,
	}

	err := this.sendMsg(event_new_call, callMsg)
	if err != nil {
		logs.Error("发送新呼叫事件失败:%v,err:%v", callId, err)
	}

	logs.Debug("发送websocket 呼入通知[%v]:%v", event_new_call, callMsg)

	return
}

//发送消息
func (this *WsClient) SendMessage(data interface{}) error {

	err := this.sendMsg(event_message, data)
	if err != nil {
		logs.Error("发送信息失败 err:%v", err)
		return err
	}

	return nil
}
